#ifndef __UDSF_SPIFLASH_C__
#define __UDSF_SPIFLASH_C__


#include "udf_global.h"
/*
*   notice:
*   UDSF 同UDF编程：不可调用cstd-lib,只可调用"sdk_ifs_udk_cfg.h"、"sys_api.h"中列出的API函数。
*   UDSF文件内函数均需使用static修饰符，且UDF中以#include "UDSF.c"形式引用
*/


/*qspi*/
#define QSPI_READ_CMD_STANDARD         (0x0Bul)
#define QSPI_READ_CMD_QUAD             (0xEBul)
#define QSPI_READ_CMD_DUAL             (0xBBul)	
#define QSPI_DUMMY_DATA_LEN_STANDARD   (0x07ul)
#define QSPI_DUMMY_DATA_LEN_QUAD       (0x05ul)		
#define QSPI_DUMMY_DATA_LEN_DUAL       (0x03ul)
#define	QSPI_BOOT_SEL_BOOT             (0x01ul)
#define	QSPI_BOOT_SEL_NORMAL           (0x00ul)	
#define	QSPI_CPOL                      (0x00ul)	
#define	QSPI_CPHA                      (0x00ul)
#define QSPI_CS_CS_LOW                 (0x00ul)	
#define QSPI_CS_CS_HIGH                (0x01ul)

//qspi flash cmd
#define WRITE_ENABLE                   (0x06)
#define CHIP_ERASE                     (0x60)
#define READ_REG1                      (0x05)
#define READ_REG2                      (0x35)
#define WRITE_REG_ENABLE               (0x50)
#define WRITE_REG1                     (0x01)

#define SECTOR_ERASE                   (0x20)
#define PAGE_PROGRAM                   (0x02)
#define READ_DATA                      (0x03)
#define REG1_BUSY_MASK                 (0x01)

#define CLK_DIV_FACTOR  (0)

static uint8_t udsf_qspi_read_cmd(uint8_t cmd)  __attribute__((unused));
static void udsf_qspi_send_cmd(uint8_t cmd) __attribute__((unused));
static void udsf_qspi_send_cmd_subcmd_data(uint8_t cmd,uint32_t subcmd,uint8_t subcmd_len,uint8_t* data,uint32_t data_len,uint8_t data_read_or_write) __attribute__((unused));
static void udsf_qspi_set_xip_disable(void) __attribute__((unused));
static void udsf_qspi_set_xip_enable(uint8_t mode) __attribute__((unused));

/*qspi*/
static uint8_t udsf_qspi_read_cmd(uint8_t cmd){
	uint8_t res;
	QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_LOW << QSPI_CS_CS_Pos);
	QSPI->DATA8[0] = cmd;         while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->DATA8[0] = QSPI_DUMMY_DATA;   while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
	res = QSPI->DATA8[0];
	return res;
}
static void udsf_qspi_send_cmd(uint8_t cmd){
	QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_LOW << QSPI_CS_CS_Pos);
	QSPI->DATA8[0] = cmd;         while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
}

static void udsf_qspi_send_cmd_subcmd_data(uint8_t cmd,uint32_t subcmd,uint8_t subcmd_len,uint8_t* data,uint32_t data_len,uint8_t data_read_or_write){
	
	QSPI->ST = QSPI_ST_IRQ_Msk;
	QSPI->CS = (QSPI_CS_CS_LOW << QSPI_CS_CS_Pos);
	QSPI->DATA8[0] = cmd;                                    while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	
	for( int i=0;i<subcmd_len;i++ ){
		QSPI->DATA8[0] = ((uint8_t*)&subcmd)[3-i];             while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
	}
	
	for( int i=0;i<data_len;i++ ){
		if( data_read_or_write == 0 ){
			QSPI->DATA8[0] = QSPI_DUMMY_DATA;                    while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
      data[i] = QSPI->DATA8[0];
		}else{
			QSPI->DATA8[0] = data[i];                            while((QSPI->ST & QSPI_ST_IRQ_Msk)==0); QSPI->ST = QSPI_ST_IRQ_Msk;
		}
	}
	
  QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
}

static void udsf_qspi_set_xip_disable(void){
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
	QSPI->CTRL =  READ_DATA  << QSPI_CTRL_READ_COMMAND_Pos|
	0  << QSPI_CTRL_TSHSL_Pos       |
	3  << QSPI_CTRL_DUMMY_LEN_Pos   |
	CLK_DIV_FACTOR  << QSPI_CTRL_CLK_DIV_Pos     |
	QSPI_STANDARD  << QSPI_CTRL_FRAME_MODE_Pos;
	QSPI->CS = (QSPI_CS_CS_HIGH << QSPI_CS_CS_Pos);
}

static void udsf_qspi_set_xip_enable(uint8_t mode){ // 0-single 1-dual 2-quad

		// xip enable
	QSPI->CS = (QSPI_CS_XIP_ON_Msk | QSPI_CS_CS_HIGH);

	if( mode == 0 ){
		
		QSPI->CTRL = (QSPI_CTRL_BOOT_SEL_Msk                                |\
			 QSPI_CTRL_MSB_SEL_Msk                                 |\
			(QSPI_STANDARD << QSPI_CTRL_FRAME_MODE_Pos)          |\
			(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
			(QSPI_DUMMY_DATA_LEN_STANDARD << QSPI_CTRL_DUMMY_LEN_Pos)  |\
			(QSPI_READ_CMD_STANDARD << QSPI_CTRL_READ_COMMAND_Pos));   
	}else if( mode == 1 ){
	QSPI->CTRL = (QSPI_CTRL_BOOT_SEL_Msk                                |\
				 QSPI_CTRL_MSB_SEL_Msk                                 |\
				(QSPI_DUAL_INPUT << QSPI_CTRL_FRAME_MODE_Pos)          |\
				(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
				(QSPI_DUMMY_DATA_LEN_DUAL << QSPI_CTRL_DUMMY_LEN_Pos)  |\
				(QSPI_READ_CMD_DUAL << QSPI_CTRL_READ_COMMAND_Pos));   
	}else if( mode == 2 ){
		QSPI->CTRL = (QSPI_CTRL_BOOT_SEL_Msk                                |\
				 QSPI_CTRL_MSB_SEL_Msk                                 |\
				(QSPI_QUAD_INPUT << QSPI_CTRL_FRAME_MODE_Pos)          |\
				(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
				(QSPI_DUMMY_DATA_LEN_QUAD << QSPI_CTRL_DUMMY_LEN_Pos)  |\
				(QSPI_READ_CMD_QUAD << QSPI_CTRL_READ_COMMAND_Pos));   
	}

	QSPI->CS = 0x0000;
	QSPI->CS = (QSPI_CS_XIP_ON_Msk | QSPI_CS_CS_HIGH);
}





/*qspi flash*/
static void udsf_spiflash_erase_fullchip(void) __attribute__((unused));
static void udsf_spiflash_erase_sector(uint32_t addr) __attribute__((unused));
static void udsf_spiflash_write_data(uint8_t* pData,uint32_t qspiAddr,int data_len) __attribute__((unused));
static void udsf_spiflash_read_data(uint8_t* pData,uint32_t qspiAddr,int data_len) __attribute__((unused));
static  int udsf_spiflash_verify_data(uint8_t* pData,uint8_t* tmp_buff,uint32_t qspiAddr,int data_len) __attribute__((unused));

static void udsf_spiflash_write_data(uint8_t* pData8,uint32_t qspiAddr,int data_len){
	
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );udsf_qspi_read_cmd(READ_REG2);
	udsf_qspi_send_cmd(WRITE_REG_ENABLE);
	udsf_qspi_send_cmd_subcmd_data(WRITE_REG1,0x02020000,2,NULL,NULL,NULL);
	udsf_qspi_send_cmd(WRITE_ENABLE);
	udsf_qspi_send_cmd_subcmd_data(PAGE_PROGRAM,qspiAddr<<8,3,pData8,data_len,1);
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );udsf_qspi_read_cmd(READ_REG2);
}
static void udsf_spiflash_read_data(uint8_t* pData8,uint32_t qspiAddr,int data_len){	
	udsf_qspi_send_cmd_subcmd_data(READ_DATA,qspiAddr<<8,3,pData8,data_len,0);// 0-read 1-write
}

static  int udsf_spiflash_verify_data(uint8_t* pData8,uint8_t *tmp_buff,uint32_t qspiAddr,int data_len){
	int res = 0;
	
	udsf_qspi_send_cmd_subcmd_data(READ_DATA,qspiAddr<<8,3,tmp_buff,data_len,0);// 0-read 1-write
	
	for (int sCnt = 0; sCnt < data_len; sCnt++){
		if(tmp_buff[sCnt] != pData8[sCnt]){
			res = -1;
			break;
		}
	}
	return res;
}
static void udsf_spiflash_erase_fullchip(void){
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );udsf_qspi_read_cmd(READ_REG2);
	udsf_qspi_send_cmd(WRITE_ENABLE);
	udsf_qspi_send_cmd(CHIP_ERASE);
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );udsf_qspi_read_cmd(READ_REG2);
}

static void udsf_spiflash_erase_sector(uint32_t addr){
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );udsf_qspi_read_cmd(READ_REG2);
	
	udsf_qspi_send_cmd(WRITE_ENABLE);
	udsf_qspi_send_cmd_subcmd_data(SECTOR_ERASE,addr<<8,3,NULL,NULL,NULL);
	
	while( (udsf_qspi_read_cmd(READ_REG1)&REG1_BUSY_MASK) );udsf_qspi_read_cmd(READ_REG2);
}

#endif

